package com.qf.gateway.filter;

import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.qf.gateway.service.TenantService;
import com.qf.gateway.utils.EncryptUtil;
import com.qf.gateway.utils.JwtUtil;
import io.jsonwebtoken.Claims;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

/**
 * 租户, 第三方系统接入, 管理员网关
 * @author 千锋健哥
 */
@Component
public class AuthFilter implements Ordered, GlobalFilter {

    @Autowired
    private TenantService tenantService;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //1. 获取请求和响应对象
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();

        //2. 获取用户请求的路径
        String path = request.getURI().getPath();

        /**
         * 3. 判断用户访问的路径,
         *      租户注册路径, 租户短信验证码路径, 租户的注销路径, 租户登录路径放行
         *      管理中心访问路径放行, 因为管理员服务中使用springSecurity授权鉴权
         */
        if (path.contains("/user")
                || path.contains("/auth/tenant/regist")
                || path.contains("/auth/checkcode/send")
                || path.contains("/auth/tenant/login")
                || path.contains("/auth/tenant/isexist")) {
            //放行
            return chain.filter(exchange);
        }

        //4. 判断如果是第三方系统接入路径, 进行鉴权
        if (path.contains("/api")) {
            //4.1 从请求头中获取accessKey, accessSecret秘钥, sign签名
            String accessKey = request.getHeaders().getFirst("access-key");
            String accessSecret = request.getHeaders().getFirst("access-securit");
            String sign = request.getHeaders().getFirst("sign");

            try {
                //4.2 判断accessKey, accessSecret秘钥, sign签名不能为空
                if (StringUtils.isEmpty(accessKey)
                        || StringUtils.isEmpty(accessSecret)
                        || StringUtils.isEmpty(sign)) {
                    //抛出401权限不足异常
                    response.setStatusCode(HttpStatus.UNAUTHORIZED);
                    return response.setComplete();
                }

                //4.3 判断sign签名是否正确, 校验规则, sign密文 = (accessKey+accessSecret)使用md5校验
                //根据规则, sign明文 = accessKey+accessSecret
                String signTemp = accessKey + accessSecret;
                //校验签名
                boolean flag = EncryptUtil.valid(signTemp, sign);

                //4.4 使用feign远程调用技术, 调用center-service基础服务的接口, 到数据库获取数据校验
                if (flag) {
                    Boolean result = tenantService.findByAccessKey(accessKey, accessSecret);
                    if (result) {
                        //将accessKey放入请求头中, 携带
                        request.mutate().header("token", accessKey);

                        //放行
                        return chain.filter(exchange);

                    }
                }
            } catch (Exception e) {
                //e.printStackTrace();
                //4.5 校验有问题,  以及其他问题抛出401权限不足异常
                response.setStatusCode(HttpStatus.UNAUTHORIZED);
                return response.setComplete();
            }

        }

        //5. 租户的其他业务访问路径, 在这里鉴权
        //5.1 从请求头中获取token令牌也就是jwt
        String token = request.getHeaders().getFirst("token");

        //5.2 判断token是否为空, 如果不为空继续鉴权
        if (StringUtils.isNotEmpty(token)) {
            try {
                //5.3 解析jwt
                Claims claims = JwtUtil.parseJWT(token);
                String subject = claims.getSubject();
                //5.4 如果解析成功将解析后的用户名放入当前请求的请求头中放行
                request.mutate().header("token", subject);
                return chain.filter(exchange);
            } catch (Exception e) {
                //e.printStackTrace();
            }
        }

        //6. 鉴权失败, 统一抛出401权限不足异常
        response.setStatusCode(HttpStatus.UNAUTHORIZED);
        return response.setComplete();

    }

    @Override
    public int getOrder() {
        return 0;
    }

}
